﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace CommonUtils
{
    public static class LinqUtil
    {
        public static T[] AddRange<T>(this IEnumerable<T> lines, params T[] appendLines)
        {
            var list = lines.ToList();
            list.AddRange(appendLines);
            return list.ToArray();
        }

        public static T[] Append<T>(this IEnumerable<T> lines, params T[] appendLines)
        => lines.AddRange(appendLines);

        public static T[] Combine<T>(this IEnumerable<T> lines, params T[] appendLines)
        => lines.AddRange(appendLines);

        public static T[] DistinctSelf<T>(this IEnumerable<T> lines)
        => lines.Distinct().ToArray();

        public static T[] OrderSelfAsc<T>(this IEnumerable<T> lines)
        => lines.OrderBy(m => m).ToArray();

        //public static T First<T>(this IEnumerable<T> lines)
        //=> lines.FirstOrDefault();

        public static void Insert<T>(this List<T> items, T value)
        => items.Insert(0, value);

        public static List<T> Reverse<T>(this List<T> items)
        {
            items.Reverse();
            return items;
        }

        #region Array
        public static T[] ToArray<T>(this ICollection collection)
        {
            var list = new List<T>();
            foreach (var item in collection)
                list.Add((T)item);
            return list.ToArray();
        }

        /// <summary>
        /// 数组取值
        /// </summary>  
        public static T Get<T>(this T[] items, int index, T defaultValue = default)
        {
            if (index < items.Length)
                return items[index];
            else
                return defaultValue;
        }

        public static int IndexOf<T>(this T[] items, T item)
        {
            for (int index = 0; index < items.Length; index++)
            {
                if (items[index].Equals(item))
                    return index;
            }
            return -1;
        }

        public static void IndexUp<T>(this T[] items, T item)
        {
            var index = items.IndexOf(item);
            if (index == 0 || index == -1)
                return;

            var temp = items[index - 1];
            items[index - 1] = items[index];
            items[index] = temp;
        }

        public static void IndexDown<T>(this T[] items, T item)
        {
            var index = items.IndexOf(item);
            if (index == items.Length - 1 || index == -1)
                return;

            var temp = items[index + 1];
            items[index + 1] = items[index];
            items[index] = temp;
        }

        /// <summary>
        /// 拆箱或者父类转子类(前提是该父类本身就是子类，只是以父类形式存在)
        /// </summary>
        public static IEnumerable<T> As<T>(this IEnumerable<object> array)
        //=> array as IEnumerable<T>值为null
        => array.Select(m => (T)m);

        /// <summary>
        /// 相同数据结构不同类之间转换，同种类或者继承类请用As
        /// </summary>
        public static IEnumerable<T> To<T>(this IEnumerable<object> array)
        => JsonUtil.Deserialize<IEnumerable<T>>(array.ToJson(true));

        public static IEnumerable<T> Each<T>(this IEnumerable<T> array, Action<T> action)
        {
            foreach (var item in array)
                action.Invoke(item);
            return array;
        }

        public static T GetRandom<T>(this T[] array)
        {
            var index = RandomUtil.Get(array.Length);
            return array[index];
        }

        public static void For<T>(this IEnumerable<T> array, Action<int, T> action)
        => array.Count().For(index => action.Invoke(index, array.ElementAt(index)));

        public static void Foreach<T>(this IEnumerable<T> array, Action<T> action)
        {
            foreach (var item in array)
                action.Invoke(item);
        }

        /// <summary>
        /// 数组截取
        /// </summary>
        public static T[] Take<T>(this IEnumerable<T> array, int skip, int length)
        => array.Skip(skip).Take(length).ToArray();

        /// <summary>
        /// 数组分割
        /// </summary> 
        public static List<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int size)
        {
            List<IEnumerable<T>> set = new List<IEnumerable<T>>();
            while (source.Count() > size)
            {
                set.Add(source.Take(size));
                source = source.Skip(size);
            }
            set.Add(source);
            return set;
        }

        public static IEnumerable<TSource> DistinctByProperty<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        {
            var items = new List<TSource>();
            foreach (var item in source)
            {
                if (items.Count(m => selector.Invoke(m).Equals(selector.Invoke(item))) == 0)
                    items.Add(item);
            }
            return items;
        }

        /// <summary>
        /// 数据库分页，一定要用在排序之后
        /// </summary>
        public static IQueryable<T> Paged<T>(this IQueryable<T> source, int pageIndex, int pageSize, out int dataAmount) where T : class
        {
            dataAmount = source.Count();
            return source.Skip(pageSize * (pageIndex - 1)).Take(pageSize);
        }

        public static bool In<T>(this T value, IEnumerable<T> values)
        => values.Contains(value);

        public static bool In<T>(this T value, params T[] values)
        => values.Contains(value);

        #endregion
    }
}
